package com.yanqu.road.logic.xlogic.rank.user;

import com.yanqu.road.entity.rank.xrank.XUserRank;
import com.yanqu.road.logic.bussiness.rank.XRankBussiness;
import com.yanqu.road.logic.pb.XRankPb;
import com.yanqu.road.logic.sort.XUserRankSort;
import com.yanqu.road.logic.xlogic.base.BaseXMap;
import com.yanqu.road.logic.xlogic.base.IChannelActivityMaxRank;
import com.yanqu.road.logic.xlogic.rank.user.entiety.XUserRankChangeParam;
import com.yanqu.road.logic.xlogic.rank.user.entiety.XUserRankChangeResult;
import com.yanqu.road.logic.xlogic.user.XUserBaseInfoLogic;
import com.yanqu.road.pb.cross3.activity.XRankProto;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 个人榜
 */
public class XUserRankMap extends BaseXMap {

    private IChannelActivityMaxRank maxRank;

    public XUserRankMap(String dbName, String tableName, IChannelActivityMaxRank maxRank) {
        super(dbName, tableName);
        this.maxRank = maxRank;
    }

    /**
     * 榜单    （活动ID，conditionType，榜单）
     */
    private final Map<Integer, Map<Integer, XUserRankListModel>> userRankMap = new ConcurrentHashMap<>();

    /**
     * 待上传榜单    （活动ID，conditionType，玩家ID，数据）
     */
    private final Map<Integer, Map<Integer, Map<Long, XUserRank>>> syncCache = new ConcurrentHashMap<>();

    /**
     * 拿榜单
     */
    public XUserRankListModel getUserRankListModel(int activityId, int conditionType) {

        if (!userRankMap.containsKey(activityId)) {
            synchronized (userRankMap) {
                if (!userRankMap.containsKey(activityId)) {
                    loadUserRankListModel(activityId); // 读数据库
                }
            }
        }

        if (!userRankMap.get(activityId).containsKey(conditionType)) {
            synchronized (userRankMap) {
                if (!userRankMap.get(activityId).containsKey(conditionType)) {
                    userRankMap.get(activityId).put(conditionType,
                            new XUserRankListModel(dbName, tableName, activityId, conditionType, maxRank.getChannelActivityMaxRank(activityId, conditionType), new XUserRankSort()));
                }
            }
        }

        return userRankMap.get(activityId).get(conditionType);
    }

    /**
     * 榜单变更
     */
    public XUserRankChangeResult userRankChange(XUserRank userRank, XUserRankChangeParam param) {

        XUserRankChangeResult changeResult = getUserRankListModel(userRank.getActivityId(), userRank.getConditionType()).rankChange(userRank, param);

        // 需要同步 && 增量 && 新上榜  =>  设置下次全量同步
        if (param.isNeedSync() && param.isUpdateBaseInfo() && changeResult.isNewInRank()) {
            XUserBaseInfoLogic.setNextAll(userRank.getActivityId(), userRank.getConditionType(), userRank.getUserId());
        }
        // 需要同步 && 榜单有变动  => 添加同步数据
        if (param.isNeedSync() && changeResult.isChange()) {
            addSyncCache(userRank);
        }

        return changeResult;
    }

    /**
     * 读库获取数据
     */
    private void loadUserRankListModel(int activityId) {
        List<XUserRank> rankList = XRankBussiness.getXUserRankList(dbName, tableName, activityId);
        // 分类
        Map<Integer, List<XUserRank>> rankListMap = new ConcurrentHashMap<>();
        for (XUserRank rank : rankList) {
            rankListMap.putIfAbsent(rank.getConditionType(), new ArrayList<>());
            rankListMap.get(rank.getConditionType()).add(rank);
        }
        // 初始化
        Map<Integer, XUserRankListModel> map = new ConcurrentHashMap<>();
        for (Map.Entry<Integer, List<XUserRank>> entry : rankListMap.entrySet()) {
            int conditionType = entry.getKey();
            List<XUserRank> userRankList = entry.getValue();
            XUserRankListModel model = new XUserRankListModel(dbName, tableName, activityId, conditionType, maxRank.getChannelActivityMaxRank(activityId, conditionType), new XUserRankSort());
            model.initByRankList(new LinkedList<>(userRankList));
            map.put(conditionType, model);
        }
        // 替换
        userRankMap.put(activityId, map);
    }

    /**
     * 获取全部榜单
     */
    public Map<Integer, Map<Integer, XUserRankListModel>> getUserRankMap() {
        return userRankMap;
    }

    /**
     * 添加待同步榜单
     */
    private void addSyncCache(XUserRank rank) {
        synchronized (syncCache) {
            if (!syncCache.containsKey(rank.getActivityId())) {
                syncCache.put(rank.getActivityId(), new ConcurrentHashMap<>());
            }
            if (!syncCache.get(rank.getActivityId()).containsKey(rank.getConditionType())) {
                syncCache.get(rank.getActivityId()).put(rank.getConditionType(), new ConcurrentHashMap<>());
            }
            Map<Long, XUserRank> rankMap = syncCache.get(rank.getActivityId()).get(rank.getConditionType());
            rankMap.put(rank.getUserId(), rank);
        }
    }

    /**
     * 获取待同步榜单 并清空
     */
    public List<XRankProto.XUserRankListMsg.Builder> getSyncCacheAndClear(boolean useUpdateMsg) {
        Map<Integer, Map<Integer, Map<Long, XUserRank>>> tmpCache;
        synchronized (syncCache) {
            if (syncCache.isEmpty()) return new ArrayList<>();
            tmpCache = new HashMap<>(syncCache);
            syncCache.clear();
        }
        List<XRankProto.XUserRankListMsg.Builder> resultList = new ArrayList<>();
        for (Map.Entry<Integer, Map<Integer, Map<Long, XUserRank>>> mapEntry : tmpCache.entrySet()) {
            int activityId = mapEntry.getKey();
            for (Map.Entry<Integer, Map<Long, XUserRank>> entry : mapEntry.getValue().entrySet()) {
                int conditionType = entry.getKey();
                Map<Long, XUserRank> rankMap = entry.getValue();
                if (rankMap.isEmpty()) continue;
                resultList.add(XRankPb.parseXUserRankListMsg(activityId, conditionType, new ArrayList<>(rankMap.values()), useUpdateMsg));
            }
        }
        return resultList;
    }

    @Override
    public void save() {
        for (Map<Integer, XUserRankListModel> modelMap : getUserRankMap().values()) {
            for (XUserRankListModel model : modelMap.values()) {
                model.save();
            }
        }
    }

    @Override
    public void loadDb(Object param) {

    }
}
